package org.commando.donquixote.erlmodleing;

import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Iterator;

public class genModule {
	private String Path = ".";
	private String ModuleName;
	private String Author = "";
	private String Exports = "";
	private String Calls = "";
	private String Casts = "";
	private String CallAPIs = "";
	private String CastAPIs = "";
	private static String CallAPITemplate = "%s(%s)  -> \n"
			+ "	gen_server:call(?MODULE, {%s%s}). \n\n\n";

	private static String callTemplate = "%%%%--------------------------------------------------------------------\n"
			+ "%%%% Function: handle_call(Request, From, State) -> {reply, Reply, State} |\n"
			+ "%%%%                                      {reply, Reply, State, Timeout} |\n"
			+ "%%%%                                      {noreply, State} |\n"
			+ "%%%%                                      {noreply, State, Timeout} |\n"
			+ "%%%%                                      {stop, Reason, Reply, State} |\n"
			+ "%%%%                                      {stop, Reason, State}\n"
			+ "%%%% Description: Handling call messages\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "handle_call({%s%s}, From, State) ->\n"
			+ "	Reply = ok,\n"
			+ "	{reply, Reply, State};\n\n\n";

	private static String castTemplate = "%%%%--------------------------------------------------------------------\n"
			+ "%%%% Function: handle_cast(Msg, State) -> {noreply, State} |\n"
			+ "%%%%                                      {noreply, State, Timeout} |\n"
			+ "%%%%                                      {stop, Reason, State}\n"
			+ "%%%% Description: Handling cast messages\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "handle_cast({%s%s}, State) ->\n" + "	{noreply, State};\n\n\n";

	private static String FileStr = "%%%%-------------------------------------------------------------------\n"
			+ "%%%% File    : %s.erl\n"
			+ "%%%% Author  :  <%s>\n"
			+ "%%%% Description :\n"
			+ "\n"
			+ "%%%%\n"
			+ "%%%% Created :  <%s>\n"
			+ "%%%%-------------------------------------------------------------------\n"
			+ "-module(%s).\n"
			+ "\n"
			+ "-behaviour(gen_server).\n"
			+ "\n"
			+ "%%%% API\n"
			+ "-export([start_link/0%s]).\n"
			+ "\n"
			+ "%%%% gen_server callbacks\n"
			+ "-export([init/1, handle_call/3, handle_cast/2, handle_info/2,\n"
			+ "		 terminate/2, code_change/3]).\n"
			+ "\n"
			+ "-record(state, {}).\n"
			+ "\n"
			+ "%%%%====================================================================\n"
			+ "%%%% API\n"
			+ "%%%%====================================================================\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "%%%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}\n"
			+ "%%%% Description: Starts the server\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "start_link() ->\n"
			+ "	gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).\n"
			+ "	\n"
			+ "%%%%API Gen\n"
			+ "%s\n"
			+ "	\n"
			+ "%s\n"
			+ "	\n"
			+ "%%%%====================================================================\n"
			+ "%%%% gen_server callbacks\n"
			+ "%%%%====================================================================\n"
			+ "\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "%%%% Function: init(Args) -> {ok, State} |\n"
			+ "%%%%                         {ok, State, Timeout} |\n"
			+ "%%%%                         ignore               |\n"
			+ "%%%%                         {stop, Reason}\n"
			+ "%%%% Description: Initiates the server\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "init([]) ->\n"
			+ "	{ok, #state{}}.\n"
			+ "\n"
			+ "%%%%call message\n"
			+ "%s\n"
			+ "%%--------------------------------------------------------------------"
			+ "%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |\n"
			+ "%%                                      {reply, Reply, State, Timeout} |\n"
			+ "%%                                      {noreply, State} |\n"
			+ "%%                                      {noreply, State, Timeout} |\n"
			+ "%%                                      {stop, Reason, Reply, State} |\n"
			+ "%%                                      {stop, Reason, State}\n"
			+ "%% Description: Handling call messages\n"
			+ "%%--------------------------------------------------------------------\n"
			+ "handle_call(_Request, _From, State) ->\n"
			+ "	Reply = ok,\n"
			+ "	{reply, Reply, State}.\n"
			+ "\n"
			+ "%%%%cast message\n"
			+ "%s\n"
			+ "%%--------------------------------------------------------------------\n"
			+ "%% Function: handle_cast(Msg, State) -> {noreply, State} |\n"
			+ "%%                                      {noreply, State, Timeout} |\n"
			+ "%%                                      {stop, Reason, State}\n"
			+ "%% Description: Handling cast messages\n"
			+ "%%--------------------------------------------------------------------\n"
			+ "handle_cast(_Msg, State) ->\n"
			+ "	{noreply, State}.\n"
			+ "\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "%%%% Function: handle_info(Info, State) -> {noreply, State} |\n"
			+ "%%%%                                       {noreply, State, Timeout} |\n"
			+ "%%%%                                       {stop, Reason, State}\n"
			+ "%%%% Description: Handling all non call/cast messages\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "handle_info(_Info, State) ->\n"
			+ "	{noreply, State}.\n"
			+ "\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "%%%% Function: terminate(Reason, State) -> void()\n"
			+ "%%%% Description: This function is called by a gen_server when it is about to\n"
			+ "%%%% terminate. It should be the opposite of Module:init/1 and do any necessary\n"
			+ "%%%% cleaning up. When it returns, the gen_server terminates with Reason.\n"
			+ "%%%% The return value is ignored.\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "terminate(_Reason, _State) ->\n"
			+ "	ok.\n"
			+ "\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "%%%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}\n"
			+ "%%%% Description: Convert process state when code is changed\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "code_change(_OldVsn, State, _Extra) ->\n"
			+ "	{ok, State}.\n"
			+ "\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "%%%% Internal functions\n"
			+ "%%%%--------------------------------------------------------------------\n"
			+ "\n\n\n";

	private static String CastAPITemplate = "%s(%s)  -> \n"
			+ "	gen_server:cast(?MODULE, {%s%s}). \n\n\n";
	
	private ArrayList<Operator> Call = new ArrayList<Operator>();

	public genModule(String name, String Path) {
		super();
		ModuleName = name;
		this.Path = Path;
	}

	private void addExport(String MsgName, String args[]) {
		Exports += String.format(", %s/%d", MsgName, args.length);
	}

	private void addCallMessage(String MsgName, String args[]) {

		String Argv = "";
		for (int i = 0; i < args.length; i++)
			Argv += ", " + args[i];
		
		if (Argv.isEmpty()){
			Argv = "  ";
		}

		System.out.println("\tcall :" + MsgName + Argv);
		Calls += String.format(callTemplate, MsgName, Argv);
		CallAPIs += String.format(CallAPITemplate, MsgName, Argv.substring(2),
				MsgName, Argv);
		addExport(MsgName, args);
	}

	private void addCastMessage(String MsgName, String args[]) {

		String Argv = "";
		for (int i = 0; i < args.length; i++)
			Argv += ", " + args[i];
		
		if (Argv.isEmpty()){
			Argv = "  ";
		}
		
		System.out.println("\tcast :" + MsgName + Argv);
		Casts += String.format(castTemplate, MsgName, Argv);
		CastAPIs += String.format(CastAPITemplate, MsgName, Argv.substring(2),
				MsgName, Argv);
		addExport(MsgName, args);
	}

	private String genFile() {
		System.out.println(this.ModuleName);
		Iterator it = Call.iterator();
		while(it.hasNext()){
			Operator Opt = (Operator)it.next();
			if(Opt.isASync()){
				addCastMessage(Opt.getName(), Opt.getParams());
			}else{
				addCallMessage(Opt.getName(), Opt.getParams());
			}
		}
		
		return String.format(FileStr, ModuleName, Author, "", ModuleName,
				Exports, CallAPIs, CastAPIs, Calls, Casts);
	}

	public void saveFile() {
		try {
			File f = new File(Path);
			if (!f.exists()) {
				f.mkdirs();
			}

			FileWriter fw = new FileWriter(Path + "/" + ModuleName + ".erl");
			fw.write(genFile());
			fw.flush();
			fw.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}

	}

	public void addOperator(Operator Opt) {
		Call.add(Opt);
	}
	
	public void setASyncBool(String OptName, boolean value) {
		Iterator it = Call.iterator();
		while(it.hasNext()){
			Operator Opt = (Operator)it.next();
			if(Opt.getName().equalsIgnoreCase(OptName)){
				Opt.setASync(value);
			}
		}
	}
}
